1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #include <stdio.h> // For printf()
19 #include <Events.h> // For WaitNextEvent()
20 #include <SIOUX.h> // For SIOUXHandleOneEvent()
22 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
23 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
27 OTLIFO serviceinfolist
;
28 Boolean headerPrinted
;
32 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
34 // These don't have to be globals, but their memory does need to remain valid for as
35 // long as the search is going on. They are declared as globals here for simplicity.
36 #define RR_CACHE_SIZE 1000
37 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
38 static mDNS mDNSStorage
;
39 static mDNS_PlatformSupport PlatformSupportStorage
;
40 static SearcherServices services
;
41 static DNSQuestion browsequestion
, domainquestion
;
43 // PrintServiceInfo prints the service information to standard out
44 // A real application might want to do something else with the information
45 static void PrintServiceInfo(SearcherServices
*services
)
47 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
51 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
52 ServiceInfo
*s
= &ls
->i
;
54 if (!services
->headerPrinted
)
56 printf("%-55s Type Domain IP Address Port Info\n", "Name");
57 services
->headerPrinted
= true;
62 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
63 ConvertDomainNameToCString(&s
->name
, c_dom
);
64 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
65 else printf("%-55s no longer available for browsing\n", c_dom
);
70 domainname type
, domain
;
71 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
72 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
73 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
74 ConvertDomainNameToCString(&type
, c_type
);
75 ConvertDomainNameToCString(&domain
, c_dom
);
76 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
78 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
79 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
80 else printf("Removed\n");
88 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
89 // enqueues a record for PrintServiceInfo() to print.
90 // Note, a browsing application would *not* normally need to get all this information --
91 // all it needs is the name, to display to the user.
92 // Finding out the address, port, and txtinfo should be deferred to the time that the user
93 // actually needs to contact the service to use it.
94 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
96 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
97 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
98 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
100 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
101 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
106 // When a new named instance of a service is found, FoundInstance() is called.
107 // In this sample code we turn around and immediately issue a query to resolve that service name to
108 // find its address, port, and txtinfo, but a normal browing application would just display the name.
109 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
111 #pragma unused (question)
112 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
113 linkedServiceInfo
*info
;
115 debugf("FoundInstance %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
117 if (answer
->rrtype
!= kDNSType_PTR
) return;
118 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
120 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
121 if (!info
) { services
->lostRecords
= true; return; }
123 info
->i
.name
= answer
->rdata
->u
.name
;
124 info
->i
.InterfaceID
= answer
->InterfaceID
;
125 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
126 info
->i
.ip
.ip
.v4
= zerov4Addr
;
127 info
->i
.port
= zeroIPPort
;
128 info
->add
= AddRecord
;
129 info
->dom
= mDNSfalse
;
131 if (!AddRecord
) // If TTL == 0 we're deleting a service,
132 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
133 else // else we're adding a new service
135 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
136 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
137 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
141 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
144 #pragma unused (question)
145 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
146 linkedServiceInfo
*info
;
148 debugf("FoundDomain %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
150 if (answer
->rrtype
!= kDNSType_PTR
) return;
151 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
153 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
154 if (!info
) { services
->lostRecords
= true; return; }
156 info
->i
.name
= answer
->rdata
->u
.name
;
157 info
->i
.InterfaceID
= answer
->InterfaceID
;
158 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
159 info
->i
.ip
.ip
.v4
= zerov4Addr
;
160 info
->i
.port
= zeroIPPort
;
161 info
->add
= AddRecord
;
162 info
->dom
= mDNStrue
;
164 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
167 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
168 static Boolean
YieldSomeTime(UInt32 milliseconds
)
170 extern Boolean SIOUXQuitting
;
172 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
173 SIOUXHandleOneEvent(&e
);
174 return(SIOUXQuitting
);
180 Boolean DoneSetup
= false;
183 SIOUXSettings
.asktosaveonclose
= false;
184 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
185 SIOUXSettings
.rows
= 40;
186 SIOUXSettings
.columns
= 132;
188 printf("Multicast DNS Searcher\n\n");
189 printf("This software reports errors using MacsBug breaks,\n");
190 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
191 printf("******************************************************************************\n");
193 err
= InitOpenTransport();
194 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
196 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
197 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
198 if (err
) return(err
);
200 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
201 tempmem
= OTAllocMem(0x10000);
202 if (tempmem
) OTFreeMem(tempmem
);
203 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
205 services
.serviceinfolist
.fHead
= NULL
;
206 services
.headerPrinted
= false;
207 services
.lostRecords
= false;
209 while (!YieldSomeTime(35))
211 #if MDNS_ONLYSYSTEMTASK
212 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
213 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
214 extern void mDNSPlatformIdle(mDNS
*const m
);
215 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
217 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
219 domainname srvtype
, srvdom
;
221 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
222 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
223 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
224 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, &services
);
226 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
230 if (services
.serviceinfolist
.fHead
)
231 PrintServiceInfo(&services
);
233 if (services
.lostRecords
)
235 services
.lostRecords
= false;
236 printf("**** Warning: Out of memory: Records have been missed.\n");
240 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
241 mDNS_Close(&mDNSStorage
);